'''
FUba PLC通讯 业务逻辑

'''
import sys
import threading
import time
import traceback

# sys.path.append(r'D:\code\git\project_format_jzbxh')
# from plc_S7.s7_client import lay1_client
# 导入layer1_client
try:
    from plc_client.layer1.factory import Lay1PLCFactory
except:
    from ..layer1.factory import Lay1PLCFactory

# 导入ABCProjectPlcClient
try:
    from plc_client.layer2.ABCProjectPlcClient import ProjectPlcClient
except:
    from ..layer2.ABCProjectPlcClient import ProjectPlcClient

try:
    from log import logger
except:
    from ...log import logger




class JZHPlcClient(ProjectPlcClient): # 津住PLC客户端逻辑
    def __init__(self, lay1_client_name = 'modbus_tcp', plc_dict={}):
        super().__init__()
        # config = {
        #     'ip': '192.168.250.1',
        #     'port': 44818,
        #     'dbnumber': 183,
        #     'name_addr_dict': { # 地址格式和plc layer1有关
        #         'p1.is_jc': 'giPress_VisionStart', # 检测触发
        #         'p1.jc_res':'giPress_VisionResult', # 检测结果
        #         # 'p2.is_jc':'giPress_VisionStart', # 检测触发
        #         # 'p2.jc_res':10,
        #         'is_ready': 0,
        #         'p1.step': 'giPress_VisionMode', # 检测步骤
        #         'giPress_VisionHeartbeat': 'giPress_VisionHeartbeat',# 心跳
        #         'bar_str': ['giPress_VisionCodeA1', 'giPress_VisionCodeA2',
        #                     'giPress_VisionCodeA3', 'giPress_VisionCodeA4',
        #                     'giPress_VisionCodeA5', 'giPress_VisionCodeA6',
        #                     'giPress_VisionCodeA7', 'giPress_VisionCodeA8'], # 条码 12345678
        #         'gstrProgramName': 'gstrProgramName', # 产品型号
        #     }
        #
        # }
        self.config = plc_dict
        self.lay1_client_name = lay1_client_name
        self.lay1_client = Lay1PLCFactory.create(lay1_client_name, self.config['ip'], self.config['port']) # 可根据lay1_client_name选择对象
        # self.lay1_client = lay1_client_class(config['ip'], config['port'])


    def connect(self):
        self.lay1_client.connect()

    def close(self):
        self.lay1_client.close()

    def isConnected(self):
        return self.lay1_client.get_connected()


    def wait_plc(self, get_trigger_signal, set_zero_trigger_signal,
                 service_var_name='p1.is_jc',step_var_name='p1.step',
                 is_continue_fun_1=None, get_step_mode_fun = None,
                 get_pnsn_fun=None,get_pnsn_fun_args=[]):  # self.get_is_scan_done, set_zero_is_scan_done
        '''
        usage:
        self.wait(self.get_is_scan_done, self.set_zero_is_scan_done)
        :param get_chufa_fun1:
        :param set_zeros_fun2:
        is_continue_fun_1: break when is_continue_fun_1 is false， 额外的结束等待条件
        get_step_mode_fun: 获取触发时的检测步骤
        todo 可扩展
        :return: int
        '''
        isDone = 0  # 1 ture 2 false
        # 等待触发
        while isDone == 0:
            isDone = get_trigger_signal(service_var_name)  #
            if is_continue_fun_1 is not None and not is_continue_fun_1():  # break when is_continue_fun_1 is false
                break
            time.sleep(0.1)  # s
        set_zero_trigger_signal(service_var_name)  # to 0
        # 获取检测步骤等
        if get_step_mode_fun is not None and get_pnsn_fun is not None:
            step_mode = get_step_mode_fun(var_name=step_var_name)
            pn, sn = get_pnsn_fun() if get_pnsn_fun_args == [] else get_pnsn_fun(get_pnsn_fun_args)
            return step_mode, pn, sn
        print(f"{service_var_name} isDone {isDone}")
        return 0

    def set_is_ready(self, is_ready):

        self.lay1_client.write_int16(start=self.config['name_addr_dict']['is_ready'], data_int16=is_ready)


    def get_trigger_signal(self, var_name='p1.is_jc'):  # 是否引导
        try:

            is_yd = self.lay1_client.read_int16(start=self.config['name_addr_dict'][var_name])

        except Exception as e:
            logger.error(e)
            logger.error(traceback.format_exc())

            self.close()
            logger.info('重连...')
            self.connect() # 重连
            logger.info('重连 done')

            return 0

        return is_yd

    def set_zero_trigger_signal(self, var_name='p1.is_jc'):  # 是否引导 置0

        self.lay1_client.write_int16(start=self.config['name_addr_dict'][var_name], data_int16=0)

        return


    def set_res(self, end, ends, service_name='p1', step_mode=0):  # 发送结果

        '''
        和step_mode有关
        '''

        status = end
        show_str_jc_res = '拍照完成'
        if service_name == 'p_right': # 右边点位
            self.lay1_client.write_int16(start=self.config['name_addr_dict'][f'{service_name}.jc_res1'], data_int16=1) # 拍照完成结果
            if step_mode == 9: # 最后一步
                self.lay1_client.write_int16(start=self.config['name_addr_dict'][f'{service_name}.jc_res2'], data_int16=status) # ng/ok
                show_str_jc_res = show_str_jc_res + f' status {end}'
        elif service_name == 'p_left': # 左边点位

            self.lay1_client.write_int16(start=self.config['name_addr_dict'][f'{service_name}.jc_res1'], data_int16=1) # 拍照完成结果
            if step_mode == 15: # 最后一步
                self.lay1_client.write_int16(start=self.config['name_addr_dict'][f'{service_name}.jc_res2'], data_int16=status) # ng/ok
                show_str_jc_res = show_str_jc_res + f' 状态 {end}'

        return show_str_jc_res




    def get_step_mode(self, var_name='giPress_VisionMode'): # 获取检测步骤

        is_yd = self.lay1_client.read_int16(start=self.config['name_addr_dict'][var_name])

        if self.lay1_client_name == 'sim':
            return is_yd
        else:
            return is_yd-1


    def set_manual_trigger(self, var_name_trigger='p1.is_jc', var_name_step_mode='giPress_VisionMode', values=[]):
        self.lay1_client.write_int16(start=self.config['name_addr_dict'][var_name_trigger], data_int16=values[0]) # 触发置1
        self.lay1_client.write_int16(start=self.config['name_addr_dict'][var_name_step_mode], data_int16=values[1])  # 检测步骤

    def write_string(self, var_name='bar_str', value='123'):
        self.lay1_client.write_string(start=self.config['name_addr_dict'][var_name],data_str=value)

    def read_string(self, var_name='gstrProgramName'): # 20240725 产品型号
        return self.lay1_client.read_string(start=self.config['name_addr_dict'][var_name])

    # def read_string(self, var_name='product_name'):
    #     pass

    def set_heart(self, var_name='var_name', value=0): # 设置心跳

        self.lay1_client.write_int16(start=self.config['name_addr_dict'][var_name], data_int16=value)


    def get_robotxyzs(self, var_name='', is_has_z = False):
        '''
        获取左右工位各步骤的机械臂坐标值，最多16个，

        return
            xyzs
        '''

        if self.lay1_client_name == 'sim':
            return {'big': [[34.6, 11.7], [-15.4, 11.7], [-65.4, 11.7], [-125.4, 1.7], [-165.4, 11.7], [-170.4, -63.3], [-115.4, -43.3], [-65.4, -43.3], [-15.4+5, -43.3], [14.6, -43.3], [34.6, -93.3], [-15.4, -93.3], [-65.4, -98.3], [-115.4, -98.3], [-165.4, -98.3]],
                    'small': [[-34.52, -23.51], [-78.0, -23.51], [-120.0, -23.51], [-120.0, -59.77], [-78.0, -59.77], [-34.52, -59.77], [-34.52, -99.05], [-78.0, -99.05], [-120.0, -99.05]]
                    }


        xyzs = {'big': [], 'small': []} # [[], []  ]
        db_int, offset_int = self.config['name_addr_dict'][var_name]
        # total = (15 + 15)*3 # 左右工位
        total = 16 # 最大个数

        # ls = []
        # for i in range(total*6):
        #     py_int = offset_int + i*4 # int16
        #     value = self.lay1_client.read_real(start=[db_int, py_int])
        #     time.sleep(0.01)
        #     print(f'py_int {py_int}')
        #     ls.append(value) # x1x15y1y15z1z15  x1x9y1y9
        ls = self.lay1_client.read_reals(start=[db_int, offset_int],numbs=total*6)
        for i in range(1,total):
            zuo_x = ls[i+0*total]/100
            zuo_y = ls[i+1*total]/100
            zuo_z = ls[i+2*total]/100

            you_x = ls[i+3*total]/100
            you_y = ls[i+4*total]/100
            you_z = ls[i+5*total]/100
            if is_has_z:
                if not (zuo_x == 0 and zuo_y==0 and zuo_z==0):
                    xyzs['big'].append([zuo_x, zuo_y, zuo_z])
                if not (you_x == 0 and you_y == 0 and you_z == 0):
                    xyzs['small'].append([you_x, you_y, you_z])
            else:
                if not (zuo_x == 0 and zuo_y == 0):
                    xyzs['big'].append([zuo_x, zuo_y])
                if not (you_x == 0 and you_y == 0):
                    xyzs['small'].append([you_x, you_y])

        return xyzs



def test_FubaPlcClient():

    hn_plc = JZHPlcClient(lay1_client_name='s7_tcp')
    hn_plc.connect()
    xyzs = hn_plc.get_robotxyzs(var_name=[49,0])

    print(xyzs)
    hn_plc.close()


if __name__ == "__main__":
    # test_HuoniPlcClinet()
    test_FubaPlcClient()
